package com.vip.xchat.config;

import com.alibaba.fastjson.JSON;
import com.vip.xchat.mapper.UserMapper;
import com.vip.xchat.model.Xchat;
import com.vip.xchat.model.Xuser;
import com.vip.xchat.service.IXChatService;
import com.vip.xchat.service.IXSessionService;
import lombok.Data;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;

@ServerEndpoint(value = "/webSocket/{userId}")
@Component
@EnableScheduling // cron定时任务
@Data
public class WebSocket {

    @Resource
    private IXChatService ixChatService;
    private static IXChatService ixChatServiceMapper;
    @Resource
    private IXSessionService ixSessionService;
    private static IXSessionService ixSessionServiceMapper;
    @Resource
    private UserMapper userMapper;
    private static UserMapper iuserMapper;

    @PostConstruct
    public void init() {
        WebSocket.ixChatServiceMapper = this.ixChatService;
        WebSocket.ixSessionServiceMapper = this.ixSessionService;
        WebSocket.iuserMapper = this.userMapper;
    }

    /**
     * concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
     */
    private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>();
    // 用来存在线连接用户信息
    private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<String, Session>();
    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * 用户ID
     */
    private String userId;

    public static CopyOnWriteArraySet<WebSocket> getWebSocketSet() {
        return webSocketSet;
    }

    public static void setWebSocketSet(CopyOnWriteArraySet<WebSocket> webSocketSet) {
        WebSocket.webSocketSet = webSocketSet;
    }

    /**
     * 连接建立成功调用的方法
     *
     * @param session 会话
     */
    @OnOpen
    public void onOpen(Session session, @PathParam(value = "userId") String userId) {
        this.userId = userId;
        this.session = session;
        sessionPool.put(userId, session);
        webSocketSet.add(this);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        System.out.println("收到客户端: " + message);
        Xchat xchat = JSON.parseObject(message, Xchat.class);
        ixChatServiceMapper.sendXChat(xchat);
        Xuser xuser = iuserMapper.selectById(xchat.getUserId());
        xchat.setUserCover(xuser.getCover());
        String userIds = ixSessionServiceMapper.getUserIdsBySession(xchat.getSessionId());
        String[] ids = userIds.split(",");
        for (String id : ids) {
            if (id.equals(xchat.getUserId()))
                xchat.setMe(true);
            else
                xchat.setMe(false);
            Session toSession = sessionPool.get(id + "@" + xchat.getSessionId());
            if (!StringUtils.isEmpty(toSession)) {
                sendMessage(toSession, xchat);
            }
        }
    }

    /**
     * 发送信息
     *
     * @param message 消息
     */
    public void sendMessage(Session session, Object message) throws IOException {
        System.out.println("发送信息: " + message);
        String json = JSON.toJSONString(message);
        session.getBasicRemote().sendText(json);
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        try {
            webSocketSet.remove(this);
            sessionPool.remove(this.userId);
            System.out.println("客户端关闭: " + this.userId);
        } catch (Exception e) {
        }
    }

    /**
     * 发生错误时调用
     *
     * @param session 会话
     * @param error   错误信息
     */
    @OnError
    public void onError(Session session, Throwable error) {
        error.printStackTrace();
    }

}